import Long from 'long';
import {WL} from './weilapb'
import {TextMsgDataParser} from "./weilapb_textmsg_parser";
import CryptoJS from 'crypto-js'
import {calculateOpusDataFrame} from "sdk/main/weila_utils";
import { WL_MsgData, WL_MsgDataStatus, WL_MsgDataType, WL_ServiceSession, WL_SessionInfo } from './weilapb_data_define';

export function hexStr2Uint8Array(hexStr: string): Uint8Array|undefined {
    if (hexStr.length % 2 == 0) {
        const hexArray = hexStr.match(/.{1,2}/g);
        if (hexArray) {
            return Uint8Array.from(hexArray.map(v => parseInt(v, 16)));
        }
    }

    return undefined;
}

export function uint8Array2HexStr(arrayBuffer: Uint8Array): string {
    if (arrayBuffer.length) {
        return arrayBuffer.reduce((previousValue, currentValue) => previousValue + currentValue.toString(16).padStart(2, '0'), '');
    }

    return '';
}

export function getStringFromBase64(base64Str: string): string {
    let base64Array = CryptoJS.enc.Base64.parse(base64Str);
    return base64Array.toString(CryptoJS.enc.Utf8);
}

// http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt

/* utf.js - UTF-8 <=> UTF-16 convertion
 *
 * Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
 * Version: 1.0
 * LastModified: Dec 25 1999
 * This library is free.  You can redistribute it and/or modify it.
 */

export function uint8Array2Utf8Str(arrayBuffer: Uint8Array): string {
    let out, i, len, c;
    let char2, char3;

    out = "";
    len = arrayBuffer.length;
    i = 0;
    while(i < len) {
        c = arrayBuffer[i++];
        switch(c >> 4)
        {
            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
            // 0xxxxxxx
            out += String.fromCharCode(c);
            break;
            case 12: case 13:
            // 110x xxxx   10xx xxxx
            char2 = arrayBuffer[i++];
            out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
            break;
            case 14:
                // 1110 xxxx  10xx xxxx  10xx xxxx
                char2 = arrayBuffer[i++];
                char3 = arrayBuffer[i++];
                out += String.fromCharCode(((c & 0x0F) << 12) |
                    ((char2 & 0x3F) << 6) |
                    ((char3 & 0x3F) << 0));
                break;
        }
    }

    return out;
}

export function getPbResultCodeMassage(resultCode: number): string {
    let msg = '';
    switch (resultCode) {
        case WL.Service.ResultCode.RESULT_SUCCESS: {
            msg = "成功";
        }break;

        case WL.Service.ResultCode.RESULT_FAILURE: {
            msg = "失败";
        }break;

        case WL.Service.ResultCode.RESULT_DISCONNECT: {
            msg = "连接中断";
        }break;

        case WL.Service.ResultCode.RESULT_NO_MSG_SERVER: {
            msg = "未连接消息服务器";
        }break;

        case WL.Service.ResultCode.RESULT_NO_DB_SERVER: {
            msg = "未连接数据服务器";
        }break;

        case WL.Service.ResultCode.RESULT_NO_CACHE_SERVER: {
            msg = "未连接缓存服务器";
        }break;

        case WL.Service.ResultCode.RESULT_NO_LOGIN_SERVER: {
            msg = "未连接登录服务器";
        }break;

        case WL.Service.ResultCode.RESULT_NO_ROUTE_SERVER: {
            msg = "未连接路由服务器";
        }break;

        case WL.Service.ResultCode.RESULT_DB_EXCEPTION: {
            msg = "数据库异常";
        }break;

        case WL.Service.ResultCode.RESULT_CACHE_EXCEPTION: {
            msg = "缓存异常";
        }break;

        case WL.Service.ResultCode.RESULT_SERVER_MAINTENANCE: {
            msg = "服务器维护中";
        }break;

        case WL.Service.ResultCode.RESULT_SERVER_EXCEPTION: {
            msg = "服务器异常";
        }break;


        case WL.Service.ResultCode.RESULT_PARAM_INVALID: {
            msg = "参数错误";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_NOT_SUPPORT: {
            msg = "请求不支持";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_LIMITED: {
            msg = "请求受限";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_INVALID: {
            msg = "请求已过期";
        }break;

        case WL.Service.ResultCode.RESULT_VERSION_TOO_OLD: {
            msg = "APP版本太旧,需要更新";
        }break;

        case WL.Service.ResultCode.RESULT_BLACKLIST_LIMITED: {
            msg = "您已被拉黑";
        }break;

        case WL.Service.ResultCode.RESULT_AUTH_INVALID: {
            msg = "认证无效";
        }break;

        case WL.Service.ResultCode.RESULT_PERMIT_LIMITED: {
            msg = "权限受限";
        }break;

        case WL.Service.ResultCode.RESULT_DATA_NOT_EXIST: {
            msg = "数据不存在";
        }break;

        case WL.Service.ResultCode.RESULT_DATA_INVALID: {
            msg = "数据无效";
        }break;

        case WL.Service.ResultCode.RESULT_VERIFICATION_CODE_ERROR: {
            msg = "验证码错误";
        }break;

        case WL.Service.ResultCode.RESULT_TOKEN_INVALID: {
            msg = "授权失效";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_FREQUENTLY: {
            msg = "请求太频繁";
        }break;

        case WL.Service.ResultCode.RESULT_NUMBER_RESOURCE_USE_UP: {
            msg = "号码资源耗尽";
        }break;

        case WL.Service.ResultCode.RESULT_REQUEST_TIMEOUT: {
            msg = "请求超时";
        }break;

        case WL.Service.ResultCode.RESULT_TRANSMIT_TIMEOUT: {
            msg = "网络传输超时";
        }break;

        case WL.Service.ResultCode.RESULT_APP_ILLEGAL: {
            msg = "应用未授权,请从官方渠道获取";
        }break;

        case WL.Service.ResultCode.RESULT_PHONE_DUPLICATE: {
            msg = "手机号已被使用";
        }break;

        case WL.Service.ResultCode.RESULT_PHONE_INVALID: {
            msg = "手机号无效";
        }break;

        case WL.Service.ResultCode.RESULT_PHONE_HAS_BEEN_BANNED: {
            msg = "手机号被封禁";
        }break;

        case WL.Service.ResultCode.RESULT_PASSWORD_ERROR: {
            msg = "密码错误";
        }break;

        case WL.Service.ResultCode.RESULT_SEND_VERIFICATION_CODE_FAIL: {
            msg = "发送验证码失败";
        }break;

        //Login Error
        case WL.Service.ResultCode.RESULT_LOGIN_FORBID_IP: {
            msg = "用户IP被封 从forbidDuration获取剩余时长(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_FORBID_USER: {
            msg = "用户被封号 从forbidDuration获取剩余时长(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_PASSWORD_ERROR_TOO_TIMES: {
            msg = "密码输入错误次数太多,请待系统解封后再试(默认30分钟后才可登录) 从forbidDuration获取剩余时长(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_SYSTEM_FULL: {
            msg = "在线用户达到系统容量";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_VERIFYCODE_INVALID: {
            msg = "验证码无效";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_ACCOUNT_OR_PASSWD_ERROR: {
            msg = "账号或密码错误(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_HAS_BIND: {
            msg = "用户已绑定设备";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_BINDING: {
            msg = "设备绑定中";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_NOT_BIND: {
            msg = "未绑定分机";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_LAWLESSNESS: {
            msg = "非法设备(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_LICENSE_LIMITED: {
            msg = "许可证用完(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_ACCOUNT_ERROR: {
            msg = "设备账号错误(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_PASSWORD_ERROR: {
            msg = "设备密码错误(设备不再自动登录)";
        }break;

        case WL.Service.ResultCode.RESULT_LOGIN_EXTENSION_OFFLINE: {
            msg = "设备不在线";
        }break;

        //User Error
        case WL.Service.ResultCode.RESULT_USER_NOT_EXIST: {
            msg = "用户不存在";
        }break;

        case WL.Service.ResultCode.RESULT_USER_PERIPHERAL_UNAUTHORIZED: {
            msg = "外设未授权";
        }break;

        case WL.Service.ResultCode.RESULT_USER_PERIPHERAL_REPLICATED: {
            msg = "外设被复制";
        }break;

        case WL.Service.ResultCode.RESULT_USER_PERIPHERAL_MULTIDEVICE: {
            msg = "外设在多设备上使用";
        }break;

        case WL.Service.ResultCode.RESULT_USER_OFFLINE: {
            msg = "用户不在线";
        }break;

        //Friend Error
        case WL.Service.ResultCode.RESULT_FRIEND_NOT_FRIEND: {
            msg = "不是好友";
        }break;

        case WL.Service.ResultCode.RESULT_FRIEND_INVITE_NOT_EXIST: {
            msg = "好友邀请已过期";
        }break;

        case WL.Service.ResultCode.RESULT_FRIEND_IS_BLACKLIST: {
            msg = "您已被对方加入黑名单  ";
        }break;

        case WL.Service.ResultCode.RESULT_FRIEND_SHIELD_OPEN: {
            msg = "好友已开启消息屏蔽   ";
        }break;


        //Group Error
        case WL.Service.ResultCode.RESULT_GROUP_NOT_EXIST: {
            msg = "群组不存在";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_ACCESS_LIMITED: {
            msg = "访问受限,请明天再试(被踢或被封)";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_YOU_ARE_NOT_OWNER: {
            msg = "您不是群主";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_YOU_ARE_NOT_ADMIN: {
            msg = "您不是群管理员";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBERS_FULL: {
            msg = "成员数达到上限";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_NUMBER_USEUP: {
            msg = "群组号耗尽";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_BROADCAST_EXIST: {
            msg = "群组广播已存在";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_BROADCAST_NOEXIST: {
            msg = "群组广播不存在";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_PASSWORD_ERROR: {
            msg = "群密码错误";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_OWNER_FULL: {
            msg = "您创建的群组数达到上限";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_BURST_OCCUPY: {
            msg = "话权被占用";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_USER_NOT_MEMBER: {
            msg = "用户不是群成员";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_LIMIT_MAX: {
            msg = "群成员上限达到最大值";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_IS_ADMIN: {
            msg = "不能对管理员进行操作";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_USER_IN_BLACKLIST: {
            msg = "用户被加入群黑名单";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_OWNER_CANNOT_EXIT: {
            msg = "群主不能退群,请先转让群主或直接删除群";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_YOU_ARE_SHUTUP: {
            msg = "你已被禁言";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_SHUTUP: {
            msg = "群成员被禁言";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_IS_OWNER: {
            msg = "不能对群主进行操作";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_BURST_REVOKE: {
            msg = "话权被回收";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_IS_EXTENSION: {
            msg = "不能对设备用户进行操作";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_COUNT_LIMIT: {
            msg = "加群数量达到上限";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_MEMBER_HAS_EXTENSION: {
            msg = "成员中存在设备用户";
        }break;

        case WL.Service.ResultCode.RESULT_GROUP_OWNER_CANNOT_EXTENSION: {
            msg = "群主不能是设备用户";
        }break;


        //Session Error
        case WL.Service.ResultCode.RESULT_SESSION_BURST_MONITOR: {
            msg = "设备正在被其他人监听,请稍后再试";
        }break;

        //Room Error
        case WL.Service.ResultCode.RESULT_ROOM_HAS_EXIST: {
            msg = "房间已存在";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_NOT_EXIST: {
            msg = "房间不存在";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_LOCK: {
            msg = "房间处于锁定状态";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_SPEAKING: {
            msg = "有人在讲话";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_CHANGE_CHARGE_LIMITED: {
            msg = "房间未锁定或有访客不允许修改计费";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_HONORED_GUEST_PERMIT: {
            msg = "只有嘉宾才允许当前操作";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_NOT_ENTRY: {
            msg = "用户未进入房间";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_YOU_ARE_HONORED_GUEST: {
            msg = "您已经是嘉宾";
        }break;

        case WL.Service.ResultCode.RESULT_ROOM_HONORED_GUEST_FULL: {
            msg = "嘉宾数量达到上限";
        }break;

        //Business Error
        case WL.Service.ResultCode.RESULT_BUSINESS_SERVICE_CLOSED: {
            msg = "服务已关闭";
        }break;

        case WL.Service.ResultCode.RESULT_BUSINESS_STAFF_INVALID: {
            msg = "不是客服号";
        }break;

        case WL.Service.ResultCode.RESULT_BUSINESS_STAFF_NOT_ONLINE: {
            msg = "客服不在线";
        }break;

        case WL.Service.ResultCode.RESULT_BUSINESS_STAFF_BUSY: {
            msg = "客服忙";
        }break;

        default: {
            msg = '';
        }
    }
    return msg;
}

export function getResultCodeFromError(errorMsg: string): number {
    const pattern = /RET_CODE:(.*)-MESSAGE:/i;
    const result = errorMsg.match(pattern);
    if (result) {
        if (result.length > 1) {
            return parseInt(result[1]);
        }
    }

    return -1;
}


export function convertFromMsgDataRaws(msgDataRaws: WL.Session.IMsgData[], myUserId: number): WL_MsgData[] {
    const count = msgDataRaws.length;
    const msgDatas: WL_MsgData[] = [];

    for (let i = 0; i < count; i++) {
        let msgData: WL_MsgData = {
            ...msgDataRaws[i]
        }
        
        if (msgDataRaws[i].sessionType == WL.Common.SessionType.SESSION_TYPE_SINGLE && msgDataRaws[i].senderId != myUserId) {
            msgData.sessionId = Long.fromValue(msgDataRaws[i].senderId!);
        }

        msgData.combo_id = getMsgDataIdByCombo(msgData, 0);

        switch (msgDataRaws[i].msgType) {
            case WL.Session.MessageType.MSG_TYPE_TEXT: {
                const textMsgData : WL_MsgData | undefined = TextMsgDataParser.decodeSessionTextMsg(msgDataRaws[i].textData!);
                if (textMsgData !== undefined) {
                    msgData.textData = textMsgData.textData;
                    msgData.fileInfo = textMsgData.fileInfo;
                    msgData.videoData = textMsgData.videoData;
                    msgData.pictureData = textMsgData.pictureData;
                    msgData.locationData = textMsgData.locationData;
                    msgData.command = textMsgData.command;
                    msgData.msgType = textMsgData.msgType;
                } else {
                    msgData.status = WL_MsgDataStatus.WL_MSG_DATA_STATUS_ERR;
                }
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_PTT: {
                msgData.msgType = WL_MsgDataType.WL_MSG_DATA_PTT_TYPE;
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_AUDIO: {
                msgData.msgType = WL_MsgDataType.WL_MSG_DATA_AUDIO_TYPE;

                if (msgDataRaws[i].audioData && msgDataRaws[i].audioData!.payload && msgDataRaws[i].audioData!.payload!.length > 0) {
                    msgData.audioData!.frameCount = calculateOpusDataFrame(msgDataRaws[i].audioData!.payload!);
                } else if (msgDataRaws[i].audioData && msgDataRaws[i].audioData!.url && msgDataRaws[i].audioData!.url !== '') {
                    const match = msgData.audioData!.url!.match(/.*\?duration=(\d+)/);
                    msgData.audioData!.frameCount = 0;
                    if (match && match.length > 1) {
                        msgData.audioData!.frameCount = parseInt(match[1]) * 50;
                    }
                } else {
                    msgData.status = WL_MsgDataStatus.WL_MSG_DATA_STATUS_ERR;
                }
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_SERVICE: {
                msgData.msgType = WL_MsgDataType.WL_MSG_DATA_SERVICE_TYPE;
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_SWITCH: {
                msgData.msgType = WL_MsgDataType.WL_MSG_DATA_SWITCH_TYPE;
            }
            break;

            case WL.Session.MessageType.MSG_TYPE_REVOCATION: {
                msgData.msgType = WL_MsgDataType.WL_MSG_DATA_WITHDRAW_TYPE;
            }
            break;

            default: {
                msgData.status = WL_MsgDataStatus.WL_MSG_DATA_STATUS_ERR;
            }
            break;
        }

        if (msgData.status != WL_MsgDataStatus.WL_MSG_DATA_STATUS_ERR) {
            msgDatas.push(msgData);
        }
    }

    return msgDatas;
}

export function getMsgDataIdByCombo(msgData: WL_MsgData, seq: number): string {
    if (msgData) {
        return `${msgData.sessionId}_${msgData.sessionType}_${msgData.msgId}_${seq}`;
    }

    return ''
}

export function convertFromSessionRaw(sessionRaws: WL.Session.ISessionInfo[], loginUserId: number): WL_SessionInfo[] {
    const sessionCount = sessionRaws.length;
    const sessions: WL_SessionInfo[] = [];
    for (let i = 0; i < sessionCount; i++) {
        let session = {
            ...sessionRaws[i]
        } as WL_SessionInfo;
        
        if (sessionRaws[i].latestMsgData) {
            [session.lastMsgData] = convertFromMsgDataRaws([sessionRaws[i].latestMsgData!], loginUserId);
        }

        sessions.push(session);
    }

    return sessions;
}
